﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace URGSystems.Umbraco.uVersionClientCache
{
    /// <summary>
    /// How should the versioned file be outputted
    /// </summary>
    public enum OutputType
    {
        /// <summary>
        /// Just file + querystring version 
        /// </summary>
        Standard,

        /// <summary>
        /// Wrap the file + querystring version in a css link tag for use in the html head section
        /// </summary>
        CSS,

        /// <summary>
        /// Wrap the file + querystring version in a script link tag
        /// </summary>
        Javascript
    }

    /// <summary>
    /// What versioning type should we use
    /// </summary>
    public enum VersionType
    {
        /// <summary>
        /// Last modified file date
        /// </summary>
        LastModifiedDate,

        /// <summary>
        /// MD5 of the file contents (text)
        /// </summary>
        MD5
    }

    public class VersionGenerator : System.Web.UI.WebControls.WebControl
    {
        public string filename { get; set; }
        private string _outputType;
        public string outputType 
        {
            get { return _outputType; }
            set { _outputType = value; }
        
        }
        private string _versionType;
        public string versionType 
        {
            get { return _versionType; }
            set { _versionType = value; }
        }

        private VersionType VersionType
        {
            get
            {
                // Default to LastModifiedDate
                VersionType version = uVersionClientCache.VersionType.LastModifiedDate;
                Enum.TryParse(versionType, out version);
                return version;
            }
        }

        private OutputType OutputType
        {
            get
            {
                // Default to Standard Output
                OutputType output = OutputType.Standard;
                Enum.TryParse(outputType, out output);
                return output;
            }
        }

        /// <summary>
        /// from http://blog.brezovsky.net/en-text-2.html
        /// </summary>
        /// <param name="input"></param>
        /// <returns></returns>
        private static string GetMD5Hash(string input)
        {
            System.Security.Cryptography.MD5CryptoServiceProvider x = new System.Security.Cryptography.MD5CryptoServiceProvider();
            byte[] bs = System.Text.Encoding.UTF8.GetBytes(input);
            bs = x.ComputeHash(bs);
            System.Text.StringBuilder s = new System.Text.StringBuilder();
            foreach (byte b in bs)
            {
                s.Append(b.ToString("x2").ToLower());
            }
            string password = s.ToString();
            return password;
        }

        private string GetVersionFromFile()
        {
            string fileUrl = filename;
            try
            {
                var mappedFilename = System.Web.HttpContext.Current.Server.MapPath(filename);
                // only version the file if it exists
                if (System.IO.File.Exists(mappedFilename))
                {
                    switch (VersionType)
                    {
                        case uVersionClientCache.VersionType.MD5:
                            using (var stream = System.IO.File.OpenText(mappedFilename))
                            {
                                string text = stream.ReadToEnd();
                                var hash = GetMD5Hash(text);
                                if (!string.IsNullOrEmpty(hash))
                                    fileUrl = string.Format("{0}?hash={1}", filename, hash);
                            }
                            break;
                        case uVersionClientCache.VersionType.LastModifiedDate:
                            DateTime lastModifiedTime = System.IO.File.GetLastWriteTime(mappedFilename);
                            fileUrl = string.Format("{0}?modified={1:yyyyMMddHHmmss}", fileUrl, lastModifiedTime);
                            break;
                    }
                }
            }
            catch (Exception)
            {
                // do nothing - just return the file name that we already have
            }
            return fileUrl;
        }

        protected override void Render(System.Web.UI.HtmlTextWriter writer)
        {
            base.Render(writer);

            var fileUrl = GetVersionFromFile();                

            switch (OutputType)
            {
                case OutputType.CSS:
                    fileUrl = string.Format("<link href='{0}' rel='stylesheet' type='text/css'>", fileUrl);
                    break;
                case OutputType.Javascript:
                    fileUrl = string.Format("<script src='{0}' type='text/javascript'></script>", fileUrl);
                    break;
                case OutputType.Standard:
                    // yes, its redundent, but just to make absolutely clear what we are doing
                    fileUrl = string.Format("{0}", fileUrl);
                    break;
            }

            writer.Write(fileUrl);
        }

    }
}
